package org.examcity.domain.fixtures;

import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;

import org.examcity.util.ReflectionUtil;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;

/**
 * Abstract class to ease the creation of persistent entities using JPA.
 * <p>
 * Concrete implementations of this class are supposed to be created only via an
 * {@link ApplicationContext} as they require dependency injection. Usually,
 * {@link FixtureUtil#create(Class)} is recommended.
 * <p>
 * Subclasses must be declared as
 * 
 * <pre>
 *  &#064;Component
 *  &#064;Scope(&quot;prototype&quot;)
 *  public class FooBuilder EntityBuilder&lt;Foo&gt;{
 *      ...
 *  }
 * </pre>
 * 
 * 
 * @author Antonio Gomes
 * @param <T> Type of the entity to create
 */
public abstract class EntityBuilder<T> implements ApplicationContextAware {

	/** Instance being created by this builder*/
	protected final T entity;
	protected final Class<T> entityType;
	protected ApplicationContext applicationContext;

	@PersistenceContext
	protected EntityManager entityManager;

	@SuppressWarnings("unchecked")
	public EntityBuilder() {
		this.entityType = (Class<T>) ReflectionUtil.getParameterType(getClass(), 0);
		entity = FixtureUtil.create(entityType);
	}

	@Override
	public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
		this.applicationContext = applicationContext;
	}

	/**
	 * Builds the instance and makes it persistent.
	 * @return newly created and persisted entity
	 */
	public T build() {
		beforeBuild();
		entityManager.persist(entity);
		afterBuild();
		return entity;
	}

	/**
	 * Invoked just after instantiating a new entity to allow subclasses to prepare the instance as
	 * needed.
	 * <p>
	 * The default implementation does nothing.
	 */
	protected void afterCreate() {
	}

	/**
	 * Invoked just before executing {@link #build()} to allow subclasses to validate and/or
	 * pre-process the instance as needed.
	 * <p>
	 * The default implementation does nothing.
	 */
	protected void beforeBuild() {
	}

	/**
	 * Invoked just after executing the method {@link #build()} to allow subclasses to post-process
	 * the instance as needed before returning it to the caller.
	 * <p>
	 * The default implementation does nothing.
	 */
	protected void afterBuild() {
	}

}
